home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 40
/
Aminet 40 (2000)(Schatztruhe)[!][Dec 2000].iso
/
Aminet
/
comm
/
tcp
/
Amster.lha
/
Amster_Install
/
Source
/
transfer.c
< prev
next >
Wrap
C/C++ Source or Header
|
2000-07-31
|
12KB
|
505 lines
/*
** Amster - Transfer
** by Jacob Laursen <laursen@myself.com>
*/
#include "include/config.h"
#include <stdio.h>
#include <stdlib.h>
#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/socket.h>
#include <netdb.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/tcp.h>
#include <bsdsocket/socketbasetags.h>
#include <error.h>
#include <time.h>
#include "include/mui.h"
#include <MUI/NListview_mcc.h>
#include "include/download.h"
#include "include/upload.h"
#include "include/gui.h"
#include "include/panel.h"
#include "include/prefs.h"
#include "include/transfer.h"
#include "amster_Cat.h"
#include "include/protos.h"
MUIF translistdisp(REG(a2) char **array, REG(a1) songtrans sd)
{
static char bufd2[50], bufd3[50], bufd4[50], bufd5[50];
static char bufu2[50], bufu3[50], bufu4[50], bufu5[50];
char *buf2, *buf3, *buf4, *buf5;
static char *states[] = {
(char *)_MSG_TRANS_STAT_PREPARE,
(char *)_MSG_TRANS_STAT_QUEUE,
(char *)_MSG_TRANS_STAT_WAIT,
(char *)_MSG_TRANS_STAT_CONN,
(char *)_MSG_TRANS_STAT_REQ,
(char *)_MSG_TRANS_STAT_INIT,
(char *)_MSG_TRANS_STAT_DL,
(char *)_MSG_TRANS_STAT_UL,
(char *)_MSG_TRANS_STAT_FIN,
(char *)_MSG_TRANS_STAT_ABORT,
(char *)_MSG_TRANS_STAT_ERROR,
NULL
};
static char *errors[] = {
(char *)_MSG_TRANS_STAT_ERROR,
(char *)_MSG_TRANS_ERROR_FILEOPEN,
(char *)_MSG_TRANS_ERROR_FILEREAD,
(char *)_MSG_TRANS_ERROR_FILEWRITE,
(char *)_MSG_TRANS_ERROR_NET_UNKNOWN,
(char *)_MSG_TRANS_ERROR_LOGGEDOUT,
(char *)_MSG_TRANS_ERROR_NOTFOUND,
(char *)_MSG_TRANS_ERROR_INVALIDREQUEST,
(char *)_MSG_TRANS_ERROR_TEASER,
(char *)_MSG_TRANS_ERROR_BUSY,
(char *)_MSG_TRANS_ERROR_NOTREQ,
(char *)_MSG_TRANS_ERROR_NET_TIMEOUT,
NULL
};
static char *NetError[] = {
(char *)_MSG_TRANS_ERROR_NET_TIMEOUT,
(char *)_MSG_TRANS_ERROR_NET_REFUSED,
(char *)_MSG_TRANS_ERROR_NET_RESET,
(char *)_MSG_TRANS_ERROR_NET_PIPE,
NULL
};
if (states[0] == (char *)_MSG_TRANS_STAT_PREPARE)
localize_array(states);
if (errors[0] == (char *)_MSG_TRANS_STAT_ERROR)
localize_array(errors);
if (NetError[0] == (char *)_MSG_TRANS_ERROR_NET_TIMEOUT)
localize_array(NetError);
if (sd) {
if (sd->type == TYPE_DOWNLOAD_OUT || sd->type == TYPE_DOWNLOAD_IN) {
buf2 = bufd2;
buf3 = bufd3;
buf4 = bufd4;
buf5 = bufd5;
}
else {
buf2 = bufu2;
buf3 = bufu3;
buf4 = bufu4;
buf5 = bufu5;
}
*array++ = nap_strippath(sd->song->title);
if (sd->state == DLS_WAIT) {
sprintf(buf5, states[sd->state], sd->ErrorCode);
*array++ = buf5;
}
else if (sd->state != DLS_ERROR)
*array++ = states[sd->state];
else {
switch (sd->error) {
case ERROR_FILEOPEN:
case ERROR_FILEREAD:
case ERROR_FILEWRITE:
sprintf(buf5, errors[sd->error], sd->ErrorCode);
*array++ = buf5;
break;
case ERROR_NET:
switch (sd->ErrorCode) {
case ETIMEDOUT:
*array++ = NetError[ERROR_NET_TIMEOUT];
break;
case ECONNREFUSED:
*array++ = NetError[ERROR_NET_REFUSED];
break;
case ECONNRESET:
*array++ = NetError[ERROR_NET_RESET];
break;
case EPIPE:
*array++ = NetError[ERROR_NET_PIPE];
break;
default:
sprintf(buf5, errors[sd->error], sd->ErrorCode);
*array++ = buf5;
}
break;
default:
*array++ = errors[sd->error];
}
}
if (sd->size > 0)
sprintf(buf2,"\33r%ld / %ld (%d%%)", sd->cur, sd->size, (sd->cur*100+5)/sd->size);
else sprintf(buf2, "\33r0"); /* Can this happen? */
*array++ = buf2;
if (sd->cps > 0) {
if (sd->stalltick < 5 || sd->state >= DLS_FIN) { /* 5 seconds */
sprintf(buf3, "%d", sd->cps);
*array++ = buf3;
}
else {
*array++ = (char *)MSG_TRANS_STAT_STALLED;
}
sprintf(buf4, "%ld:%02ld / %ld:%02ld", sd->transtime/60, sd->transtime%60, sd->timeleft/60, sd->timeleft%60);
*array = buf4;
}
else {
*array++ = "-";
*array = "-";
}
}
else {
*array++ = (char *)MSG_LH_FILE;
*array++ = (char *)MSG_LH_STATE;
*array++ = (char *)MSG_LH_SIZE;
*array++ = (char *)MSG_LH_CPS;
*array = (char *)MSG_LH_ETIME;
}
return 0;
}
MUIF translistdest(REG(a2) APTR pool, REG(a1) songtrans sd)
{
nap_songfree(sd->song);
if (sd->fname) free(sd->fname);
free(sd);
return 0;
}
ULONG dl_setup(struct IClass *cl, Object *obj, Msg msg)
{
struct TransferData *data = INST_DATA(cl, obj);
if (!DoSuperMethodA(cl, obj, msg))
return(FALSE);
DoMethod(_app(obj), MUIM_Application_AddInputHandler, &data->ihnode);
/* DoMethod(_app(obj), MUIM_Application_AddInputHandler, &data->watchnode);*/
return(TRUE);
}
ULONG dl_muicleanup(struct IClass *cl, Object *obj, Msg msg)
{
struct TransferData *data = INST_DATA(cl,obj);
DoMethod(_app(obj), MUIM_Application_RemInputHandler, &data->ihnode);
/* DoMethod(_app(obj), MUIM_Application_RemInputHandler, &data->watchnode);*/
return(DoSuperMethodA(cl,obj,msg));
}
void CalculateCps(songtrans sd)
{
if (sd->cur != sd->oldsize) {
sd->stalltick = 0;
sd->oldsize = sd->cur;
}
else sd->stalltick++;
sd->transtime = time(NULL) - sd->starttime;
if (sd->transtime == 0) sd->transtime = 1;
sd->cps = (sd->cur - sd->resumestart) / sd->transtime;
if (sd->cps > 0)
sd->timeleft = (sd->size - sd->cur) / sd->cps;
else sd->timeleft = 0;
}
void TransferSetError(struct TransferData *data, char *title, char *user, int error)
{
u_long tmp;
songtrans sd;
long i;
for (i=0; ; i++) {
DoMethod(data->list, MUIM_NList_GetEntry, i, &tmp);
if (!tmp) return;
sd = (songtrans)tmp;
if (strcmp(sd->song->title, title) == 0 && stricmp(sd->song->user, user) == 0) break;
}
if ((sd->type == TYPE_DOWNLOAD_OUT || sd->type == TYPE_DOWNLOAD_IN) && sd->state == DLS_PREP) {
DoMethod(gui->dwin, DL_COUNTDECREMENT);
}
sd->state = DLS_ERROR;
sd->error = error;
if (sd->type == TYPE_DOWNLOAD_OUT || sd->type == TYPE_DOWNLOAD_IN) DoMethod(gui->dwin, DL_UPDATE, sd);
else DoMethod(gui->uwin, UPLOAD_UPDATE, sd);
}
void TransferInfo(struct TransferData *data)
{
static char bufd[600], bufu[600];
char *buf;
u_long tmp;
songtrans sd;
GetAttr(MUIA_NList_EntryClick, data->list, &tmp);
if (tmp == -1 || tmp == -2) return;
DoMethod(data->list, MUIM_NList_GetEntry, tmp, &sd);
if (!sd) return;
if (sd->song->ip == 0) return;
if (sd->type == TYPE_DOWNLOAD_OUT || sd->type == TYPE_DOWNLOAD_IN) buf = bufd;
else buf = bufu;
if (sd->host[0] == '\0') {
sprintf(buf, "%s (%d.%d.%d.%d)", sd->song->user, (sd->song->ip&0xFF000000)>>24, (sd->song->ip&0xFF0000)>>16, (sd->song->ip&0xFF00)>>8, sd->song->ip&0xFF);
}
else {
sprintf(buf, "%s (%s)", sd->song->user, sd->host);
}
set(data->info, MUIA_Text_Contents, buf);
}
void TransferAbort(struct TransferData *data)
{
u_long item;
songtrans sd;
DoMethod(data->list, MUIM_NList_GetEntry, MUIV_NList_GetEntry_Active, &item);
if (!item) return;
sd = (songtrans)item;
if (sd->state >= DLS_FIN) {
return;
}
if (sd->type == TYPE_DOWNLOAD_OUT || sd->type == TYPE_DOWNLOAD_IN) {
if (sd->state == DLS_WAIT) DoMethod(gui->dwin, DL_REMWAITING, sd);
if (sd->state == DLS_QUEUE) QueueCount--;
}
if (sd->t) {
th_message(sd->t, THC_EXIT, 0);
Signal(sd->t->task, SIGBREAKF_CTRL_C);
}
else {
if (sd->type == TYPE_DOWNLOAD_OUT || sd->type == TYPE_DOWNLOAD_IN) {
if (sd->state != DLS_QUEUE && sd->state != DLS_WAIT) {
DoMethod(gui->dwin, DL_COUNTDECREMENT);
}
}
else DoMethod(gui->uwin, UPLOAD_COUNTDECREMENT);
}
sd->state = DLS_ABORT;
if (sd->type == TYPE_DOWNLOAD_OUT || sd->type == TYPE_DOWNLOAD_IN) DoMethod(gui->dwin, DL_UPDATE, sd);
else DoMethod(gui->uwin, UPLOAD_UPDATE, sd);
}
void TransferCleanup(struct TransferData *data)
{
u_long item;
int i=0;
set(data->list, MUIA_NList_Quiet, MUIV_NList_Quiet_Visual);
while (1) {
DoMethod(data->list, MUIM_NList_GetEntry, i, &item);
if (!item) break;
if (((songtrans)item)->state >= DLS_FIN) DoMethod(data->list, MUIM_NList_Remove, i);
else i++;
}
set(data->list,MUIA_NList_Quiet, MUIV_NList_Quiet_None);
}
void TransferCleanupSingle(struct TransferData *data, songtrans sd)
{
long pos;
pos = MUIV_NList_GetPos_Start;
DoMethod(data->list, MUIM_NList_GetPos, sd, &pos);
DoMethod(data->list, MUIM_NList_Remove, pos);
}
void TransferWatcher(struct TransferData *data)
{
u_long item;
long i;
songtrans sd;
for (i=0; ; i++) {
DoMethod(data->list, MUIM_NList_GetEntry, i, &item);
if (!item) break;
sd = (songtrans)item;
if (sd->state == DLS_PREP) {
if (time(NULL)-sd->reqtime > 120) { /* We consider this transfer dead/hanging (never started) */
sd->state = DLS_ERROR;
sd->error = ERROR_TIMEOUT;
if (sd->type == TYPE_DOWNLOAD_OUT || sd->type == TYPE_DOWNLOAD_IN) {
DoMethod(gui->dwin, DL_COUNTDECREMENT);
DoMethod(gui->dwin, DL_UPDATE, sd);
}
else {
DoMethod(gui->uwin, UPLOAD_COUNTDECREMENT);
DoMethod(gui->uwin, UPLOAD_UPDATE, sd);
}
}
}
}
}
void TransferHandleError(songtrans sd)
{
char error[128];
if (sd->ErrorCode == EINTR) return; /* Aborted with CTRL-C */
if (sd->error != 0) {
sd->state = DLS_ERROR;
if (sd->error >= ERROR_FILEOPEN && sd->error <= ERROR_FILEWRITE) {
Fault(sd->ErrorCode, "", error, 127);
gui_debugf((char *)MSG_INFO_IOERROR, sd->fname, error);
}
else if (sd->error >= ERROR_OUTOFBOUND) sd->error = ERROR_UNKNOWN;
prf_event(PRFE_DLERROR, sd->fname);
}
else if (sd->state == DLS_FIN) {
if (sd->type == TYPE_DOWNLOAD_OUT || sd->type == TYPE_DOWNLOAD_IN) prf_event(PRFE_DLFINISH, sd->fname);
else prf_event(PRFE_ULFINISH, sd->fname);
}
if (sd->type == TYPE_DOWNLOAD_OUT || sd->type == TYPE_DOWNLOAD_IN) DoMethod(gui->dwin, DL_UPDATE, sd);
else DoMethod(gui->uwin, UPLOAD_UPDATE, sd);
}
/* Thread stuff */
BOOL InitTransferThread(thread t, songtrans sd)
{
struct Library *DosBase;
struct Library *SocketBase;
char *buffer;
long s;
long tmp;
struct hostent *he;
sd->state = DLS_PREP;
sd->nsig = AllocSignal(-1);
if (sd->nsig == -1) {
ExitTransferThread(sd, 49);
return FALSE;
}
sd->nsigm = (1L << (sd->nsig));
sd->msigm = (1L << (t->port->mp_SigBit));
DosBase = OpenLibrary("dos.library", 0);
if (!DosBase) {
ExitTransferThread(sd, 50);
return FALSE;
}
sd->DosBase = DosBase;
SocketBase = OpenLibrary("bsdsocket.library", 0);
if (!SocketBase) {
ExitTransferThread(sd, 51);
return FALSE;
}
sd->SocketBase = SocketBase;
SocketBaseTags(SBTM_SETVAL(SBTC_SIGIOMASK), (char *)sd->nsigm, TAG_DONE);
buffer = malloc(8192);
if (!buffer) {
ExitTransferThread(sd, 52);
return FALSE;
}
sd->buffer = buffer;
/* Perform DNS-lookup */
he = gethostbyname(Inet_NtoA(sd->song->ip));
he = gethostbyaddr(he->h_addr_list[0], he->h_length, AF_INET);
if (he != 0) strcpy(sd->host, he->h_name);
else strcpy(sd->host, Inet_NtoA(sd->song->ip));
s = socket(AF_INET, SOCK_STREAM, 0);
if (s < 0) {
ExitTransferThread(sd, 53);
return FALSE;
}
sd->s = s;
sd->sin.sin_addr.s_addr = sd->ip;
sd->sin.sin_port = htons(sd->port);
sd->sin.sin_family = AF_INET;
sd->sin.sin_len = sizeof(sd->sin);
tmp = 1;
IoctlSocket(s, FIOASYNC, (char *)&tmp);
IoctlSocket(s, FIONBIO, (char *)&tmp);
/* Asynchronous and non-blocking I/O to the socket */
tmp = connect(s, (struct sockaddr *)&sd->sin, sizeof(sd->sin));
if (tmp == -1 && Errno() != EINPROGRESS) {
sd->ErrorCode = Errno();
ExitTransferThread(sd, ERROR_NET);
return FALSE;
}
thr_message(t, DLC_STATE, (APTR)DLS_CON);
return TRUE;
}
void ExitTransferThread(songtrans sd, int ret)
{
struct Library *DosBase=sd->DosBase;
struct Library *SocketBase=sd->SocketBase;
if (sd->nsig != -1) FreeSignal(sd->nsig);
sd->nsig = -1;
if (sd->f) Close(sd->f);
sd->f = 0;
if (sd->s != -1) CloseSocket(sd->s);
sd->s = -1;
if (sd->buffer) free(sd->buffer);
sd->buffer = NULL;
if (SocketBase) CloseLibrary(SocketBase);
sd->SocketBase = NULL;
if (DosBase) CloseLibrary(DosBase);
sd->DosBase = NULL;
thr_exit(sd->t, ret);
}